#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/uaccess.h>


int major;
static int minor = 0;
static int hello_open(struct inode *inode, struct file *file);
static ssize_t hello_read(struct file *file, char __user *buf, size_t count, loff_t *ppos);
static ssize_t hello_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos);
long hello_ioctl(struct file *file, unsigned int cmd, unsigned long arg);  

static dev_t devno;
static struct class *cls;
static struct device *test_device;

static char test_buff[128]; 

struct file_operations hello_fileop = {     
    .owner = THIS_MODULE,    
    .open = hello_open,
    .read = hello_read,
    .write = hello_write,
    .unlocked_ioctl = hello_ioctl
};


static int hello_open(struct inode *inode, struct file *file)
{
    printk(KERN_ALERT"|----------------|\n");
    printk(KERN_ALERT"|                |\n");
    printk(KERN_ALERT"|   hello_open   |\n");
    printk(KERN_ALERT"|      *OvO*     |\n");
    printk(KERN_ALERT"|                |\n");
    printk(KERN_ALERT"|----------------|\n");
    return 0;
}

static ssize_t hello_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
    strcat(test_buff, " from kernel!");
    if (0 != copy_to_user(buf, test_buff, strlen(test_buff))) {
        printk(KERN_ALERT"ERROR:  read error!");
    }
    printk(KERN_ALERT"|----------------|\n");
    printk(KERN_ALERT"|                |\n");
    printk(KERN_ALERT"|   hello_read   |\n");
    printk(KERN_ALERT"|      *O3O*     |\n");
    printk(KERN_ALERT"|                |\n");
    printk(KERN_ALERT"|----------------|\n");
    return 0;
}

static ssize_t hello_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
    memset(test_buff, 0, sizeof(test_buff));
    if (0 != copy_from_user(test_buff, buf, count)) {
        printk(KERN_ALERT"ERROR:  write error!");
    }
    printk(KERN_ALERT"|----------------|\n");
    printk(KERN_ALERT"|                |\n");
    printk(KERN_ALERT"|   hello_write  |\n");
    printk(KERN_ALERT"|      *OxO*     |\n");
    printk(KERN_ALERT"|                |\n");
    printk(KERN_ALERT"|----------------|\n");
    return 0;
}

  
long  hello_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    if (cmd == 1) {
    	printk(KERN_ALERT"|----------------|\n");
    	printk(KERN_ALERT"|   HELLO  ECNU  |\n");
    	printk(KERN_ALERT"|   hello_ioctl  |\n");
    	printk(KERN_ALERT"|      CMD 1     |\n");
    	printk(KERN_ALERT"|     success    |\n");
    	printk(KERN_ALERT"|----------------|\n");
        return 0;
    }
    if (cmd == 4) {
        printk(KERN_ALERT"|----------------|\n");
    	printk(KERN_ALERT"|   ECNU  HELLO  |\n");
    	printk(KERN_ALERT"|   hello_ioctl  |\n");
    	printk(KERN_ALERT"|      CMD 2     |\n");
    	printk(KERN_ALERT"|     success    |\n");
    	printk(KERN_ALERT"|----------------|\n");
        return 0;
    }
    if (cmd == 3) {
        printk(KERN_ALERT"|----------------|\n");
    	printk(KERN_ALERT"|   your number  |\n");
    	printk(KERN_ALERT"|   hello_ioctl  |\n");
    	printk(KERN_ALERT"|      CMD 3     |\n");
    	printk(KERN_ALERT"|   your  name   |\n");
    	printk(KERN_ALERT"|----------------|\n");
        return 0;
    }

    printk("hello_ioctl error\n");
    return -EFAULT;
}  
        
static int hello_init(void)
{
    printk(KERN_ALERT"|----------------|\n");
    printk(KERN_ALERT"|                |\n");
    printk(KERN_ALERT"|   hello_init   |\n");
    printk(KERN_ALERT"|      *OvO*     |\n");


    major = register_chrdev(0, "hello", &hello_fileop);
    devno = MKDEV(major, minor);
    cls = class_create(THIS_MODULE, "hello_class");

    if (IS_ERR(cls)) {
        unregister_chrdev(major, "hello");
        printk(KERN_ALERT"|   IS_ERR(cls)  |\n");
        printk(KERN_ALERT"|----------------|\n");
        return -EBUSY;
    }

    test_device = device_create(cls, NULL, devno, NULL, "hello");

    if (IS_ERR(test_device)) {
        class_destroy(cls);
        unregister_chrdev(major, "hello");
        printk(KERN_ALERT"| IS_ERR(device)-|\n");
        printk(KERN_ALERT"|----------------|\n");
        return -EBUSY;
    }
    printk(KERN_ALERT"|                |\n");
    printk(KERN_ALERT"|----------------|\n");
    return 0;
}

static void hello_exit(void)
{
    printk(KERN_ALERT"|----------------|\n");
    printk(KERN_ALERT"|                |\n");
    printk(KERN_ALERT"|   hello_exit   |\n");
    printk(KERN_ALERT"|      mO.Om     |\n");
    printk(KERN_ALERT"|                |\n");
    printk(KERN_ALERT"|----------------|\n");

    device_destroy(cls, devno);
    class_destroy(cls);
    unregister_chrdev(major, "hello");
}

module_init(hello_init);
module_exit(hello_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("YOURNAME"); 
